<script lang="ts" setup>
import type { RolePermissionItem } from '#/api/system/model/rolesModel'
import SysRolesApi from '#/api/system/roles'
import { listToTree } from '#/helper/treeHelper'
import { $t } from '@vben/locales'
import { CheckboxGroup, Empty, message, Spin, Tree } from 'ant-design-vue'
import type { TreeDataItem } from 'ant-design-vue/es/tree'
import { throttle } from 'lodash-es'
import { computed, nextTick, ref, unref, watch } from 'vue'

defineOptions({
    name: 'SetPermissionModal'
})

const props = withDefaults(
    defineProps<{
        disabled?: boolean
        rowId?: number | string
    }>(),
    {
        rowId: '',
        disabled: false
    }
)

const emit = defineEmits(['success', 'loadingChange'])
const menuListData = ref<RolePermissionItem[]>([])
const treeData = computed(() => {
    const arr = menuListData.value.map((v) => {
        return {
            ...v,
            title: $t(v.title)
        }
    })
    return listToTree(arr) as TreeDataItem[]
})

const TreeRef = ref<InstanceType<typeof Tree>>()
// 已选中
const checkedKeys = ref<number[]>([])
const expandedKeys = ref<number[]>([])

const isLoading = ref(true)

// 处理过的树形数据 主要用于最后一级需要平铺
const treeDataShow = computed(() => {
    const arr = unref(treeData.value)
    return processTreeData(arr)
})

watch(
    () => props.rowId,
    (val) => {
        loadData(val)
    },
    {
        immediate: true
    }
)

watch(
    isLoading,
    (val) => {
        emit('loadingChange', val)
    },
    {
        immediate: true
    }
)

// 节流 防止点击太快导致请求太多
const submitThrottle = throttle(() => {
    if (isLoading.value) {
        return
    }

    submit()
}, 500)

watch(checkedKeys, submitThrottle, {
    deep: true
})

// 获取权限数据
async function loadData(id: number | string) {
    if (id) {
        isLoading.value = true
        const retMenuList = await SysRolesApi.inst.getMenuList(id)

        // 展开所有
        retMenuList.forEach((v) => {
            const { pid } = v
            if (!expandedKeys.value.includes(pid)) {
                expandedKeys.value.push(pid)
            }
        })
        // 选中的
        checkedKeys.value = retMenuList
            .filter((v) => {
                // 父级过滤掉
                return v.checked && !expandedKeys.value.includes(v.id)
            })
            .map((v) => v.id)
        menuListData.value = retMenuList
        nextTick(() => {
            isLoading.value = false
        })
    } else {
        menuListData.value = []
    }
}

// 保存权限
async function submit() {
    const id = props.rowId
    if (id) {
        // 找到所有选中的节点对应的父级 ID
        const findParentIds = (
            nodes: TreeDataItem[],
            selectedIds: number[],
            parents: number[] = []
        ) => {
            nodes.forEach((node) => {
                if (node.children && node.children.length > 0) {
                    findParentIds(node.children, selectedIds, [...parents, node.id as number])
                }
                if (selectedIds.includes(node.id as number)) {
                    parents.forEach((id) => {
                        if (!selectedIds.includes(id)) {
                            selectedIds.push(id)
                        }
                    })
                }
            })
        }

        // 复制一份 checkedKeys 进行处理
        const updatedCheckedKeys = [...checkedKeys.value]
        findParentIds(treeData.value, updatedCheckedKeys)

        // 调用 API 保存
        await SysRolesApi.inst.savePermission(id, updatedCheckedKeys)
        message.success($t('page.system.children.role.children.permission.setSuccess'))
        emit('success')
    }
}

/**
 * 处理树形数据，将最后一级的children移动到leafData属性
 * @param treeData 树形数据
 * @returns 处理后的树形数据
 */
function processTreeData<T extends { children?: T[] }>(
    treeData: T[]
): (T & { leafData?: Array<{ label: string; value: number }> })[] {
    return treeData.map((node) => {
        const result = { ...node } as T & {
            leafData?: Array<{ label: string; value: number }>
        }

        // 如果有children属性
        if (result.children && result.children.length > 0) {
            // 检查是否为最后一级节点（子节点没有children或children为空数组）
            const isLastLevel = result.children.every(
                (child) => !child.children || child.children.length === 0
            )

            if (isLastLevel) {
                // 如果是最后一级，将children存入leafData
                result.leafData = [...result.children].map((v) => {
                    return {
                        // @ts-ignore
                        label: v.title,
                        // @ts-ignore
                        value: v.id
                    }
                })
                // 隐藏子节点
                result.children.forEach((v) => {
                    // @ts-ignore
                    v.class = 'hidden'
                })

                // delete result.children
            } else {
                // 如果不是最后一级，递归处理children
                result.children = processTreeData(result.children)
            }
        }

        return result
    })
}

/**
 *
 * @param values 选中的值
 * @param leafData 字节点的值
 * @param pid 父节点id
 */
function onCheck(values: number[], leafData: Array<{ label: string; value: number }>, pid: number) {
    const allValues = leafData.map((v) => v.value)

    const keys = unref(checkedKeys)
    allValues.forEach((v) => {
        // 选中
        if (values.includes(v)) {
            if (!keys.includes(v)) {
                keys.push(v)
            }
        } else {
            // 取消选中
            const index = keys.indexOf(v)

            if (index !== -1) {
                keys.splice(index, 1)
            }
        }
    })
    // 全不选，父级不选
    if (values.length === 0) {
        const index = keys.indexOf(pid)
        if (index !== -1) {
            keys.splice(index, 1)
        }
    }

    checkedKeys.value = keys
}
</script>
<template>
    <div class="permission-tree">
        <Spin
            v-if="treeDataShow.length > 0"
            :tip="`${$t('common.loading')}...`"
            :spinning="isLoading"
        >
            <div class="flex">
                <Tree
                    ref="TreeRef"
                    v-model:checked-keys="checkedKeys"
                    v-model:expanded-keys="expandedKeys"
                    :field-names="{ title: 'title', key: 'id' }"
                    :tree-data="treeDataShow"
                    :disabled="disabled"
                    default-expand-all
                    checkable
                    block-node
                >
                    <template #title="{ title, id, leafData }">
                        <div>{{ title }}</div>
                        <div
                            v-if="leafData?.length"
                            class="grid-container"
                            :class="{
                                'leaf-open': expandedKeys.includes(id)
                            }"
                            @click.stop
                        >
                            <div class="leaf-content">
                                <div class="mt-2 w-full bg-gray-50 p-3">
                                    <CheckboxGroup
                                        :disabled="disabled"
                                        :value="checkedKeys"
                                        :options="leafData"
                                        style="row-gap: 8px"
                                        @change="onCheck($event as number[], leafData, id)"
                                    />
                                </div>
                            </div>
                        </div>
                    </template>
                </Tree>
            </div>
        </Spin>
        <Empty v-else-if="rowId && !isLoading" />
    </div>
</template>

<style lang="scss" scoped>
.permission-tree {
    :deep(.ant-tree .ant-tree-checkbox) {
        align-self: flex-start !important;
    }

    :deep(.ant-tree .ant-tree-treenode.hidden) {
        display: none !important;
    }
}

.grid-container {
    display: grid;
    grid-template-rows: 0fr; /* 初始状态高度为0 */
    overflow: hidden;
    transition: grid-template-rows 0.1s ease-out;
}

.grid-container.leaf-open {
    grid-template-rows: 1fr; /* 展开时高度自适应 */
}

.leaf-content {
    min-height: 0; /* 关键：允许内容收缩 */
}
</style>
